package com.ruoyi.datastatistics.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.basedata.domain.ElectricityTerminalsXb;
import com.ruoyi.basedata.domain.TerminalsXb;
import com.ruoyi.basedata.mapper.TerminalsDbMapper;
import com.ruoyi.basedata.mapper.TerminalsXbMapper;
import com.ruoyi.basedata.service.IElectricityTerminalsXbService;
import com.ruoyi.basedata.service.ITerminalsXbService;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.enums.Supplier;
import com.ruoyi.common.utils.DateUtil;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.HttpUtils;
import com.ruoyi.common.utils.QBTUtil;
import com.ruoyi.datastatistics.domain.*;
import com.ruoyi.datastatistics.domain.recvdata.RecvDataXb;
import com.ruoyi.datastatistics.mapper.*;
import com.ruoyi.datastatistics.service.*;
import com.ruoyi.system.service.ISysDictDataService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author zhangjie
 */
@Service
public class DataServiceImpl implements IDataService {

    public static final String NUMBER_LC_E = "1000000";
    public static final String NUMBER_LC_W = "10000";
    public static final String NUMBER_TYPE_ALL = "0";
    @Autowired
    IElectricityMeterHistoryDataService iElectricityMeterHistoryDataService;

    @Autowired
    IElectricityRealtimegatherdataXbService iElectricityRealtimegatherdataXbService;

    @Autowired
    IMeterHistoryDataService iMeterHistoryDataService;

    @Autowired
    IRealtimegatherdataXbService iRealtimegatherdataXbService;

    @Autowired
    IElectricityTerminalsXbService iElectricityTerminalsXbService;

    private final String TENANT_ID = "710733";

    private static final String QBT_GET_DAY_DOSAGE_DATA_URL =  "http://qbttmeter.com:8086/qbt/api/device";
    private static final String R_NUM_E =  "5000";
    public static final String NUMBER_ADDR_ALL = "0";
    private static final String REVERSAL_NUM_E =  "0";


    private static final String R_NUM_W =  "500";
    private static final String REVERSAL_NUM_W =  "5";

    private static final String DATE_PATTERN =  "yyyy-MM-dd";
    private static final String DATE_TIME_PATTERN =  "yyyy-MM-dd HH:mm:ss";

    private final Integer SUCCESS_CODE = 0;

    private final Integer TIMEOUT_KEY_ERROR_CODE = 5;

    private static final Logger log = LoggerFactory.getLogger(DataServiceImpl.class);

    @Autowired
    private ITerminalsXbService terminalsXbService;

    @Autowired
    private IRealtimegatherdataXbService realtimegatherdataXbService;

    @Autowired
    ISysDictDataService iSysDictDataService;


    // public static void main(String[] args) {
    //     Map<String,  String> paramsSign = null;
    //     Map<String,  String>   paramsRequeest = null;
    //     HttpUtils httpUtils = new HttpUtils();
    //     String historyJson = null;
    //     paramsRequeest = new HashMap<>(8);
    //     paramsSign = QBTUtil.GetSignData();
    //     if(paramsSign == null || paramsSign.isEmpty() ){
    //         log.error("获取不到paramsSign，任务终止。");
    //         return ;
    //     }
    //     try {
    //         historyJson = httpUtils.post("http://qbttmeter.com:8086/qbt/api/findUserAndMeterReadingData",
    //                 new ObjectMapper().writeValueAsString(paramsRequeest));
    //         System.out.println("===============================================data===============" + historyJson);
    //     }
    //     catch(Exception e){
    //             log.error("获取【千宝通】实时信息异常！");
    //         }
    //     }
    //
    //
    //  }

    /**
     * 拉取最新的数据入历史表 实时表  水表
     *
     * @param terminalIds 接收到的设备ids
     * @return 是否成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveRealLastDataWater(List<String> terminalIds, LocalDateTime checkoutDate) {
        if(ObjectUtils.isEmpty(checkoutDate)){
            log.error("结账时间为必填参数，请确认！");
            return false;
        }
        Map<String,  String> paramsSign = null;
        Map<String,  String>   paramsRequeest = null;
        HttpUtils httpUtils = new HttpUtils();
        String historyJson = null;
        paramsRequeest = new HashMap<>(8);
        paramsSign = QBTUtil.GetSignData();
        if(paramsSign == null || paramsSign.isEmpty() ){
            log.error("获取不到paramsSign，任务终止。");
            return false;
        }
        initRequestParams(checkoutDate, paramsRequeest, paramsSign);

        try {
            historyJson = httpUtils.post(QBT_GET_DAY_DOSAGE_DATA_URL, new ObjectMapper().writeValueAsString(paramsRequeest));
            if(StringUtils.isBlank(historyJson)){
                log.error("获取【千宝通】实时信息异常,返回信息为空！");
            }else{
                //第二次请求
                paramsSign = QBTUtil.GetSignData();
                if(paramsSign == null || paramsSign.isEmpty() ){
                    log.error("获取不到paramsSign，任务终止。");
                    return false;
                }
                initRequestParams(checkoutDate.minusDays(1L), paramsRequeest, paramsSign);
                historyJson = httpUtils.post(QBT_GET_DAY_DOSAGE_DATA_URL, new ObjectMapper().writeValueAsString(paramsRequeest));
                if(StringUtils.isBlank(historyJson)){
                    log.error("获取【千宝通】TWO实时信息异常,返回信息为空！");
                    return  false;
                }
            }

            TerminalHistoryResponseEnergy_QBT terminalDbHistoryResponse = JSON.parseObject(historyJson
                    , TerminalHistoryResponseEnergy_QBT.class);
            if(TIMEOUT_KEY_ERROR_CODE.intValue()  ==   terminalDbHistoryResponse.getErrNo().intValue()){
                log.error("【千宝通】获取Key或者id错误,请确认！");
                return  false;
            }else if (ObjectUtils.isNotEmpty(terminalDbHistoryResponse)  && SUCCESS_CODE.intValue()
                    == terminalDbHistoryResponse.getErrNo().intValue()) {
                String data = terminalDbHistoryResponse.getData();
                if (StringUtils.isBlank(data)) {
                    log.error("未获取到【千宝通】设备实时信息！");
                    return  false;
                }
                List<TerminalRealDataQBT> terminalHistoryDataQBTList = JSON.parseArray
                        (data, TerminalRealDataQBT.class);

                if (CollectionUtils.isEmpty(terminalHistoryDataQBTList)) {
                    log.error("未获取到【千宝通】历史信息！");
                    return false;
                }
                //校验是否过滤
                if(CollectionUtils.isNotEmpty(terminalIds)){
                    terminalHistoryDataQBTList = terminalHistoryDataQBTList.stream().filter(e->
                                    !terminalIds.contains(e.getIAddr()))
                            .collect(Collectors.toList());
                }
                //构建数据
                List<MeterHistoryData> list = contrcutHistoryWater(terminalHistoryDataQBTList);
                //满转逻辑插入
                List<RealtimegatherdataXb> listPrev = getListPrev(list);
                if(CollectionUtils.isEmpty(listPrev)){
                    log.info("==========千宝通数据实时同步失败，无实时数据==========");
                    return  false;
                }

                Result result = getResult();

                List<TerminalsXb>  terminalsXbList = terminalsXbService.list();
                List<String>  terminalIdsNoDeal = new ArrayList<>();
                for (MeterHistoryData xbData : list){
                    if(ObjectUtils.isEmpty(xbData.getTerminalId())){
                        continue;
                    }
                    Optional<RealtimegatherdataXb>  optional = listPrev.stream().filter(item -> xbData.getTerminalId()
                            .equals(item.getTerminalId())).findFirst();
                    Optional<TerminalsXb> optionalXb = getTerminalsXb(xbData, optional, terminalsXbList);
                    if (optionalXb == null) {
                        terminalIdsNoDeal.add(xbData.getTerminalId());
                        continue;
                    }
                    TerminalsXb terminalsXb = optionalXb.get();
                    BigDecimal lc = getLc(result, terminalsXb);
                    if (optional == null) {
                        setHistoryData(xbData, terminalsXb, lc);
                        continue;
                    }
                    RealtimegatherdataXb meterHistoryDataPrev = optional.get();

                    //如果获取到的实时数据 时间 小于实时数据时间 直接跳过  无需插入历史表和更新实时表  2025-11-08
                    if(!DateUtils.parseDate(xbData.getReadDate()).after(meterHistoryDataPrev.getReadDate())){
                        terminalIdsNoDeal.add(xbData.getTerminalId());
                        continue;
                    }
                    //start

                    if(ObjectUtils.isEmpty(xbData.getTotalFlow()) ||  ObjectUtils.isEmpty(meterHistoryDataPrev.getTotalFlowS())){
                        setHistoryData(xbData, terminalsXb, lc);
                        continue;
                    }
                    if(isExceptionData(xbData, lc, meterHistoryDataPrev, result.RNum, result.reversalNum)
                    ){
                        setHistoryData(xbData, terminalsXb, lc);
                    }else{ //  满转计算
                        if(isFullStatusData(xbData, meterHistoryDataPrev, result.reversalNum)){
                            updateDeviceCycNum(terminalsXb);
                        }
                        setHistoryData(xbData, terminalsXb, lc);
                    }
                }

                if(CollectionUtils.isNotEmpty(terminalIdsNoDeal)){
                    list = list.stream().filter(e->!terminalIdsNoDeal.contains(e.getTerminalId())).collect(Collectors.toList());
                }

                //插入数据
                if(CollectionUtils.isNotEmpty( list)){
                    boolean successAddMin = iMeterHistoryDataService.batchinsertMeterHistoryDataR(list) > 0;
                    if (!successAddMin) {
                        throw new RuntimeException("插入xb历史表失败！");
                    }
                    updateOrInsertRealDataWater(list);
                }
              }
            } catch (Exception e) {
                throw new RuntimeException("获取【千宝通】历史信息异常" + e);
            }
            log.info("==========千宝通数据同步完成==========");
        return true;
    }

    private List<RealtimegatherdataXb> getListPrev(List<MeterHistoryData> list) {
        RealtimegatherdataXb realtimegatherdataXb = new RealtimegatherdataXb();
        realtimegatherdataXb.setTenantId(list.get(0).getTenantId());
        List<RealtimegatherdataXb> listPrev = realtimegatherdataXbService
                .selectListAll(realtimegatherdataXb);
        return listPrev;
    }

    @NotNull
    private static BigDecimal getLc(Result result, TerminalsXb terminalsXb) {
        Optional<SysDictData> typeOp =   result.moduleTypeList.stream().filter(e->e.getDictValue().
                        equals(terminalsXb.getTypeId()))
                .findFirst();
        BigDecimal  lc = typeOp.isPresent()?new BigDecimal(typeOp.get().getRemark()):new BigDecimal(NUMBER_LC_W);
        return lc;
    }

    @NotNull
    private Result getResult() {
        SysDictData sysDictData  =  new SysDictData();
        sysDictData.setStatus("0");
        List<SysDictData> sysDictDataList =  iSysDictDataService.selectDictDataList(sysDictData);
        List<SysDictData> moduleTypeList =  sysDictDataList.stream().filter(e->"module_type".equals(e.getDictType()))
                .collect(Collectors.toList());
        Optional<SysDictData>  dayMaxQuantityElectricityOp =  sysDictDataList.stream().filter(e->"day_max_quantity_water"
                .equals(e.getDictType())).findFirst();
        Optional<SysDictData>  dayReversalNumElectricityOp =  sysDictDataList.stream().filter(e->"day_reversal_num_water"
                .equals(e.getDictType())).findFirst();

        BigDecimal RNum = dayMaxQuantityElectricityOp.isPresent()?new BigDecimal(dayMaxQuantityElectricityOp.get().getDictValue())
                :new BigDecimal(R_NUM_W);
        BigDecimal  reversalNum = dayReversalNumElectricityOp.isPresent()?new BigDecimal(dayReversalNumElectricityOp.get().getDictValue())
                :new BigDecimal(REVERSAL_NUM_W);
        Result result = new Result(moduleTypeList, RNum, reversalNum);
        return result;
    }

    private static class Result {
        public final List<SysDictData> moduleTypeList;
        public final BigDecimal RNum;
        public final BigDecimal reversalNum;

        public Result(List<SysDictData> moduleTypeList, BigDecimal RNum, BigDecimal reversalNum) {
            this.moduleTypeList = moduleTypeList;
            this.RNum = RNum;
            this.reversalNum = reversalNum;
        }
    }

    private void updateDeviceCycNum(TerminalsXb terminalsXb) {
        BigDecimal  cyclesNum = ObjectUtils.isEmpty(terminalsXb.getCyclesNum())? BigDecimal.ZERO
                : new BigDecimal(terminalsXb.getCyclesNum());
        terminalsXb.setCyclesNum(cyclesNum.add(BigDecimal.ONE).intValue());
        boolean isSuccess = terminalsXbService.updateById(terminalsXb);
        if(!isSuccess){
            throw   new RuntimeException("更新失败");
        }
    }

    private static boolean isFullStatusData(MeterHistoryData xbData, RealtimegatherdataXb meterHistoryDataPrev, BigDecimal reversalNum) {
        return meterHistoryDataPrev.getTotalFlowS().compareTo(
                xbData.getTotalFlow()) > 0
                &&
                meterHistoryDataPrev.getTotalFlowS().subtract(
                        xbData.getTotalFlow()).compareTo(reversalNum) > 0;
    }

    private static boolean isExceptionData(MeterHistoryData xbData, BigDecimal lc, RealtimegatherdataXb meterHistoryDataPrev, BigDecimal RNum, BigDecimal reversalNum) {
        return (xbData.getTotalFlow().compareTo(lc) > 0)
                || (// 与上次读数差大于R值
                xbData.getTotalFlow().subtract(meterHistoryDataPrev.getTotalFlowS()).abs().compareTo(RNum) > 0
                        &&  //突变情况  突变满转
                        //当前读数-上次读数<0 (该值在数据字典里设置，作为叶轮倒转的误差值)$t<|当前读数-上次读数|
                        // 上次读数>当前读数  &&  非倒转:  上次读数-当前读数 > 叶轮倒转的数值
                        !(meterHistoryDataPrev.getTotalFlowS().compareTo(xbData.getTotalFlow()) > 0
                                &&
                                meterHistoryDataPrev.getTotalFlowS().subtract(xbData.getTotalFlow()).compareTo(reversalNum) > 0
                        )
        );
    }

    @Nullable
    private static Optional<TerminalsXb> getTerminalsXb(MeterHistoryData xbData, Optional<RealtimegatherdataXb> optional, List<TerminalsXb> terminalsXbList) {
        if(!optional.isPresent()){
            log.error("【德高】数据库无该终端数据！getTerminalId:"
                    + xbData.getTerminalId());
            return null;
        }
        Optional<TerminalsXb>  optionalXb = terminalsXbList.stream().filter(item -> item.getTerminalId()
                .equals(xbData.getTerminalId())).findFirst();
        if(!optionalXb.isPresent()){
            log.error("【德高】数据库无该终端xb！getTerminalId:"
                    + xbData.getTerminalId());
            return null;
        }
        return optionalXb;
    }

    private static void initRequestParams(LocalDateTime checkoutDate, Map<String, String> paramsRequeest, Map<String, String> paramsSign) {
        String currentDate = checkoutDate.format(DateTimeFormatter.ofPattern(DATE_PATTERN));
        paramsRequeest.putAll(paramsSign);
        paramsRequeest.put("addr", NUMBER_ADDR_ALL);
        paramsRequeest.put("type", NUMBER_TYPE_ALL);
        paramsRequeest.put("time", currentDate);
    }

    private void setHistoryData(MeterHistoryData xbData, TerminalsXb electricityTerminalsXb, BigDecimal lc) {
        xbData.setLocationNb(electricityTerminalsXb.getLocationNb());
        if(ObjectUtils.isEmpty(xbData.getTotalFlow())){
            return;
        }
        xbData.setTotalFlowS(xbData.getTotalFlow());
        BigDecimal positiveActiveEnergyS = xbData.getTotalFlowS();
        BigDecimal  cyclesNum = ObjectUtils.isEmpty(electricityTerminalsXb.getCyclesNum())? BigDecimal.ZERO
                : new BigDecimal(electricityTerminalsXb.getCyclesNum());
        //设置展示读数
        xbData.setTotalFlow(cyclesNum.multiply(lc).add(positiveActiveEnergyS));
        xbData.setReadNumber(xbData.getTotalFlow());
        xbData.setCreateDate(new Date());
    }

    @NotNull
    private List<MeterHistoryData> contrcutHistoryWater(List<TerminalRealDataQBT> terminalHistoryDataQBTList) {
        List<MeterHistoryData> list = new ArrayList<>();
        for(TerminalRealDataQBT terminalHistoryDataQBT : terminalHistoryDataQBTList){
            MeterHistoryData meterHistoryData = new MeterHistoryData();
            meterHistoryData.setTenantId(TENANT_ID);
            meterHistoryData.setSupplierId(Supplier.QIAN_BAO_TONG.getId());
            meterHistoryData.setTerminalId(terminalHistoryDataQBT.getIAddr());
            meterHistoryData.setTotalFlow(terminalHistoryDataQBT.getShowValue());
            meterHistoryData.setTotalFlowS(terminalHistoryDataQBT.getShowValue());
            meterHistoryData.setReadDate(DateUtils.parseDateToStr(DATE_TIME_PATTERN
                    , terminalHistoryDataQBT.getReadTime()));
            meterHistoryData.setReadNumber(terminalHistoryDataQBT.getShowValue());
            meterHistoryData.setReverseNumber(BigDecimal.ZERO);
            list.add(meterHistoryData);
        }
        return list;
    }

    private void updateOrInsertRealDataWater(List<MeterHistoryData> list) {
        RealtimegatherdataXb xb =  new RealtimegatherdataXb();
        xb.setTenantId(list.get(0).getTenantId());
        List<RealtimegatherdataXb> electricityRealtimegatherdataXbList
                =  iRealtimegatherdataXbService.selectListAll(xb);
        List<RealtimegatherdataXb> listRealInsertMin = new ArrayList<>();
        List<RealtimegatherdataXb> listRealUpdateMin = new ArrayList<>();
        int  i = 0;
        for (MeterHistoryData electricityMeterHistoryData : list){
            Optional<RealtimegatherdataXb> electricityRealtimegatherdataXbOptional = getRealtimegatherdataXb(
                    electricityMeterHistoryData, electricityRealtimegatherdataXbList);
            if(electricityRealtimegatherdataXbOptional.isPresent()){
                dealUpdateBean(electricityMeterHistoryData, electricityRealtimegatherdataXbOptional, listRealUpdateMin);
            }else {
                dealAddBean(electricityMeterHistoryData, listRealInsertMin);
            }
        }
        if (CollectionUtils.isNotEmpty(listRealInsertMin)){
            boolean successAddRealMin =  iRealtimegatherdataXbService
                    .batchinsertRealtimegatherdataXbR(listRealInsertMin) > 0;
            if(!successAddRealMin){
                throw  new RuntimeException("插入xb实时表失败！");
            }
        }
        if (CollectionUtils.isNotEmpty(listRealUpdateMin)){
            boolean successUpdateRealMin =  iRealtimegatherdataXbService
                    .updateBatchById(listRealUpdateMin);
            if(!successUpdateRealMin){
                throw  new RuntimeException("更新xb实时表失败！");
            }
        }
    }

    @NotNull
    private static Optional<RealtimegatherdataXb> getRealtimegatherdataXb(MeterHistoryData electricityMeterHistoryData, List<RealtimegatherdataXb> electricityRealtimegatherdataXbList) {
        Optional<RealtimegatherdataXb> electricityRealtimegatherdataXbOptional =
                electricityRealtimegatherdataXbList.stream().filter(item ->
                        item.getTerminalId().equals(electricityMeterHistoryData.getTerminalId())  &&
                                item.getTenantId().equals(electricityMeterHistoryData.getTenantId())).findFirst();
        return electricityRealtimegatherdataXbOptional;
    }

    private static void dealAddBean(MeterHistoryData electricityMeterHistoryData, List<RealtimegatherdataXb> listRealInsertMin) {
        RealtimegatherdataXb realtimegatherdataXbAdd = new RealtimegatherdataXb();
        BeanUtils.copyProperties(electricityMeterHistoryData, realtimegatherdataXbAdd,"readDate");
        realtimegatherdataXbAdd.setReadDate(DateUtils.parseDate(electricityMeterHistoryData.getReadDate()));
        realtimegatherdataXbAdd.setId(null);
        listRealInsertMin.add(realtimegatherdataXbAdd);
    }

    private static void dealUpdateBean(MeterHistoryData electricityMeterHistoryData, Optional<RealtimegatherdataXb> electricityRealtimegatherdataXbOptional, List<RealtimegatherdataXb> listRealUpdateMin) {
        RealtimegatherdataXb realtimegatherdataXb
                = electricityRealtimegatherdataXbOptional.get();

        if(!DateUtils.parseDate(electricityMeterHistoryData.getReadDate()).after(realtimegatherdataXb.getReadDate())){
            return;
        }
        realtimegatherdataXb.setTotalFlow(electricityMeterHistoryData
                .getTotalFlow());
        realtimegatherdataXb.setTotalFlowS(electricityMeterHistoryData
                .getTotalFlowS());
        realtimegatherdataXb.setReadDate(DateUtils.parseDate(electricityMeterHistoryData.getReadDate()));
        realtimegatherdataXb.setLocationNb(electricityMeterHistoryData.getLocationNb());
        listRealUpdateMin.add(realtimegatherdataXb);
    }


    private void updateOrInsertRealDataElectricity(List<ElectricityMeterHistoryData> listMin) {
        ElectricityRealtimegatherdataXb xb =  new ElectricityRealtimegatherdataXb();
        xb.setTenantId(listMin.get(0).getTenantId());
        List<ElectricityRealtimegatherdataXb> electricityRealtimegatherdataXbList
                =  iElectricityRealtimegatherdataXbService.selectRealtimegatherdataXbListForJob(xb);
        List<ElectricityRealtimegatherdataXb> listRealInsertMin = new ArrayList<>();
        List<ElectricityRealtimegatherdataXb> listRealUpdateMin = new ArrayList<>();
        for (ElectricityMeterHistoryData electricityMeterHistoryData : listMin){
            Optional<ElectricityRealtimegatherdataXb> electricityRealtimegatherdataXbOptional =
                    electricityRealtimegatherdataXbList.stream().filter(item ->
                            item.getTerminalId().equals(electricityMeterHistoryData.getTerminalId())  &&
                                    item.getTenantId().equals(electricityMeterHistoryData.getTenantId())).findFirst();
            if(electricityRealtimegatherdataXbOptional.isPresent()){
                dealUpdateBeanE(electricityMeterHistoryData, electricityRealtimegatherdataXbOptional, listRealUpdateMin);
            }else {
                ElectricityRealtimegatherdataXb electricityRealtimegatherdataXbAdd = new ElectricityRealtimegatherdataXb();
                BeanUtils.copyProperties(electricityMeterHistoryData,electricityRealtimegatherdataXbAdd);
                electricityRealtimegatherdataXbAdd.setId(null);
                listRealInsertMin.add(electricityRealtimegatherdataXbAdd);
            }
        }
        if (CollectionUtils.isNotEmpty(listRealInsertMin)){
            boolean successAddRealMin =  iElectricityRealtimegatherdataXbService
                    .batchinsertElectricityRealtimegatherdataXb(listRealInsertMin) > 0;
            // boolean successAddRealMin =  iElectricityRealtimegatherdataXbService.saveBatch(listRealInsertMin) ;
            if(!successAddRealMin){
                throw  new RuntimeException("插入xb实时表失败！");
            }
        }
        if (CollectionUtils.isNotEmpty(listRealUpdateMin)){
            boolean successUpdateRealMin =  iElectricityRealtimegatherdataXbService
                    .updateBatchById(listRealUpdateMin);
            if(!successUpdateRealMin){
                throw  new RuntimeException("更新电-xb实时表失败！");
            }
        }
    }

    private static void dealUpdateBeanE(ElectricityMeterHistoryData electricityMeterHistoryData, Optional<ElectricityRealtimegatherdataXb> electricityRealtimegatherdataXbOptional, List<ElectricityRealtimegatherdataXb> listRealUpdateMin) {
        ElectricityRealtimegatherdataXb electricityRealtimegatherdataXb
                = electricityRealtimegatherdataXbOptional.get();
        electricityRealtimegatherdataXb.setPositiveActiveEnergy(electricityMeterHistoryData
                .getPositiveActiveEnergy());
        electricityRealtimegatherdataXb.setCombinationActiveEnergy1(electricityMeterHistoryData
                .getCombinationActiveEnergy1());
        electricityRealtimegatherdataXb.setReadDate(electricityMeterHistoryData.getReadDate());
        electricityRealtimegatherdataXb.setLocationNb(electricityMeterHistoryData.getLocationNb());
        listRealUpdateMin.add(electricityRealtimegatherdataXb);
    }


    @NotNull
    private static String getTableName(LocalDateTime currentDate) {
        // return "v9_hour_e" + currentDate.getYear()  +  (currentDate.getMonthValue() < 10?
        return "yds6000.v9_hour_e" + currentDate.getYear()  +  (currentDate.getMonthValue() < 10?
                "0" + currentDate.getMonthValue():currentDate.getMonthValue());
    }

    @Override
    public boolean saveRealLastDataEletricity(List<String> terminalIds , LocalDateTime checkoutDate) {
        if(ObjectUtils.isEmpty(checkoutDate)){
            log.error("结账时间为必填参数，请确认！");
            return false;
        }
        Map<String,  Object>   paramsRequeest = new HashMap<>(8);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_TIME_PATTERN);
        LocalDateTime checkoutDatePrev  = checkoutDate.minusHours(24L);
        int monthValuePrve = checkoutDatePrev.getMonth().getValue();
        int monthValue = checkoutDate.getMonth().getValue();
        initRequestParamsE(checkoutDate, paramsRequeest, checkoutDatePrev);

        if(CollectionUtils.isNotEmpty(terminalIds)){
            paramsRequeest.put("terminalIds", terminalIds);
        }
        List<ElectricityMeterHistoryData> list = iElectricityMeterHistoryDataService
                .selectElectricityMeterHistoryDataLasted
                        (paramsRequeest);
        List<String> listTerminalId = list.stream().map(e->e.getTerminalId()).collect(Collectors.toList());
        if(monthValuePrve != monthValue) {
            dealMoreData(paramsRequeest, checkoutDatePrev, list, listTerminalId);
        }
        //考虑 边界问题  如果是不跨月  则查单表    否则2表联查
        //  时间需要转化为  时间戳
        //获取最新的时候数据  从小时表获取 最近24小时
        List<ElectricityMeterHistoryData> listMin = list;
        if (CollectionUtils.isEmpty(listMin)) {
            log.error("【德高】数据库无最新实时数据！");
            return false;
        }

        List<ElectricityTerminalsXb> listXb = getElectricityTerminalsXbs();
        if (listXb == null) {
            return false;
        }

        List<ElectricityRealtimegatherdataXb> listPrev = getElectricityRealtimegatherdataXbs();
        if (listPrev == null) {
            return false;
        }

        List<String>  terminalIdsNoDeal = new ArrayList<>();
        listMin.stream().forEach(e->{
            if(ObjectUtils.isNotEmpty(e.getPositiveActiveEnergy())){
                e.setPositiveActiveEnergyS(e.getPositiveActiveEnergy());
            }
        });
        for (ElectricityMeterHistoryData electricityMeterHistoryData : listMin) {
            if(ObjectUtils.isEmpty(electricityMeterHistoryData.getTerminalId())){
                continue;
            }
            Optional<ElectricityRealtimegatherdataXb> optional = getElectricityRealtimegatherdataXb(electricityMeterHistoryData, listPrev);
            if (optional == null){
                continue;
            }
            ElectricityRealtimegatherdataXb electricityMeterHistoryDataPrev = optional.get();
            //如果获取到的实时数据 时间 小于实时数据时间 直接跳过  无需插入历史表和更新实时表  2025-11-08
            if(!electricityMeterHistoryData.getReadDate().after(
                    electricityMeterHistoryDataPrev.getReadDate())){
                terminalIdsNoDeal.add(electricityMeterHistoryData.getTerminalId());
            }
        }
        if(CollectionUtils.isNotEmpty(terminalIdsNoDeal)){
            list = list.stream().filter(e->!terminalIdsNoDeal.contains(e.getTerminalId())).collect(Collectors.toList());
        }
        if(CollectionUtils.isNotEmpty(list)){
            boolean successAddMin = iElectricityMeterHistoryDataService.batchinsertMeterHistoryDataR(listMin) > 0;
            if (!successAddMin) {
                throw new RuntimeException("插入xb历史表失败！");
            }
            updateOrInsertRealDataElectricity(listMin);
        }
        return true;
    }

    private void updateCycNumE(ElectricityTerminalsXb electricityTerminalsXb) {
        BigDecimal cyclesNum = ObjectUtils.isEmpty(electricityTerminalsXb.getCyclesNum()) ? BigDecimal.ZERO
                : new BigDecimal(electricityTerminalsXb.getCyclesNum());
        electricityTerminalsXb.setCyclesNum(cyclesNum.add(BigDecimal.ONE).intValue());
        iElectricityTerminalsXbService.updateById(electricityTerminalsXb);
    }

    private static boolean isFullDataStatusE(ElectricityMeterHistoryData electricityMeterHistoryData, ElectricityRealtimegatherdataXb electricityMeterHistoryDataPrev, ResultE result) {
        return electricityMeterHistoryDataPrev.getPositiveActiveEnergyS().compareTo(
                electricityMeterHistoryData.getPositiveActiveEnergyS()) > 0
                &&
                electricityMeterHistoryDataPrev.getPositiveActiveEnergyS().subtract(
                        electricityMeterHistoryData.getPositiveActiveEnergyS()).compareTo(result.reversalNum) > 0;
    }

    private static boolean isExceptionDataE(ElectricityMeterHistoryData electricityMeterHistoryData, BigDecimal lc, ElectricityRealtimegatherdataXb electricityMeterHistoryDataPrev, ResultE result) {
        return (electricityMeterHistoryData.getPositiveActiveEnergyS().compareTo(lc) > 0)
                || (// 与上次读数差大于R值
                electricityMeterHistoryData.getPositiveActiveEnergyS().subtract
                        (electricityMeterHistoryDataPrev.getPositiveActiveEnergyS()).abs().compareTo(result.RNum) > 0
                        &&  //突变情况  突变满转
                        //当前读数-上次读数<0 (该值在数据字典里设置，作为叶轮倒转的误差值)$t<|当前读数-上次读数|
                        // 上次读数>当前读数  &&  非倒转:  上次读数-当前读数 > 叶轮倒转的数值
                        !(electricityMeterHistoryDataPrev.getPositiveActiveEnergyS().compareTo(
                                electricityMeterHistoryData.getPositiveActiveEnergyS()) > 0
                                &&
                                electricityMeterHistoryDataPrev.getPositiveActiveEnergyS().subtract(
                                        electricityMeterHistoryData.getPositiveActiveEnergyS()).compareTo(result.reversalNum) > 0
                        )
        );
    }

    @NotNull
    private static BigDecimal getLcE(ResultE result, ElectricityTerminalsXb electricityTerminalsXb) {
        Optional<SysDictData> typeOp = result.moduleTypeList.stream().filter(e -> e.getDictValue().equals(electricityTerminalsXb
                        .getTypeId()))
                .findFirst();
        BigDecimal lc = typeOp.isPresent() ? new BigDecimal(typeOp.get().getRemark()) : new BigDecimal(NUMBER_LC_E);
        return lc;
    }

    @Nullable
    private static Optional<ElectricityTerminalsXb> getElectricityTerminalsXb(ElectricityMeterHistoryData electricityMeterHistoryData, List<ElectricityTerminalsXb> listXb) {
        Optional<ElectricityTerminalsXb> optionalXb = listXb.stream().filter(item -> electricityMeterHistoryData.getTerminalId()
                .equals(item.getTerminalId())).findFirst();
        if (!optionalXb.isPresent()) {
            log.error("【德高】数据库无该终端xb数据！getTerminalId:"
                    + electricityMeterHistoryData.getTerminalId());
            return null;
        }
        return optionalXb;
    }

    @Nullable
    private static Optional<ElectricityRealtimegatherdataXb> getElectricityRealtimegatherdataXb(ElectricityMeterHistoryData electricityMeterHistoryData, List<ElectricityRealtimegatherdataXb> listPrev) {
        Optional<ElectricityRealtimegatherdataXb> optional = listPrev.stream().filter(item ->
                item.getTerminalId()
                .equals(electricityMeterHistoryData.getTerminalId())).findFirst();
        if (!optional.isPresent()) {
            log.error("【德高】数据库无该终端数据！getTerminalId:"
                    + electricityMeterHistoryData.getTerminalId());
            return null;

        }
        return optional;
    }

    @Nullable
    private List<ElectricityRealtimegatherdataXb> getElectricityRealtimegatherdataXbs() {
        ElectricityRealtimegatherdataXb realtimegatherdataXb = new ElectricityRealtimegatherdataXb();
        realtimegatherdataXb.setTenantId(TENANT_ID);
        List<ElectricityRealtimegatherdataXb> listPrev = iElectricityRealtimegatherdataXbService
                .selectRealtimegatherdataXbListForJob(realtimegatherdataXb);
        if (CollectionUtils.isEmpty(listPrev)) {
            log.error("【德高】数据库电表前一天无数据！");
            return null;
        }
        return listPrev;
    }

    @Nullable
    private List<ElectricityTerminalsXb> getElectricityTerminalsXbs() {
        LambdaQueryWrapper<ElectricityTerminalsXb> wrapperXb = Wrappers.lambdaQuery();
        wrapperXb.eq(ElectricityTerminalsXb::getTenantId, TENANT_ID);
        List<ElectricityTerminalsXb> listXb = iElectricityTerminalsXbService.list(wrapperXb);
        if (CollectionUtils.isEmpty(listXb)) {
            log.error("【德高】数据库无终端！");
            return null;
        }
        return listXb;
    }

    @NotNull
    private ResultE getResultE() {
        SysDictData sysDictData = new SysDictData();
        sysDictData.setStatus("0");
        List<SysDictData> sysDictDataList = iSysDictDataService.selectDictDataList(sysDictData);
        List<SysDictData> moduleTypeList = sysDictDataList.stream().filter(e -> "module_type".equals(e.getDictType()))
                .collect(Collectors.toList());
        Optional<SysDictData> dayMaxQuantityElectricityOp = sysDictDataList.stream().filter(e -> "day_max_quantity_electricity"
                .equals(e.getDictType())).findFirst();
        Optional<SysDictData> dayReversalNumElectricityOp = sysDictDataList.stream().filter(e -> "day_reversal_num_electricity"
                .equals(e.getDictType())).findFirst();

        BigDecimal RNum = dayMaxQuantityElectricityOp.isPresent() ? new BigDecimal(dayMaxQuantityElectricityOp.get().getDictValue())
                : new BigDecimal(R_NUM_E);
        BigDecimal reversalNum = dayReversalNumElectricityOp.isPresent() ? new BigDecimal(dayReversalNumElectricityOp.get().getDictValue())
                : new BigDecimal(REVERSAL_NUM_E);
        ResultE result = new ResultE(moduleTypeList, RNum, reversalNum);
        return result;
    }

    private static class ResultE {
        public final List<SysDictData> moduleTypeList;
        public final BigDecimal RNum;
        public final BigDecimal reversalNum;

        public ResultE(List<SysDictData> moduleTypeList, BigDecimal RNum, BigDecimal reversalNum) {
            this.moduleTypeList = moduleTypeList;
            this.RNum = RNum;
            this.reversalNum = reversalNum;
        }
    }

    private void dealMoreData(Map<String, Object> paramsRequeest, LocalDateTime checkoutDatePrev, List<ElectricityMeterHistoryData> list, List<String> listTerminalId) {
        paramsRequeest.put("tableNameTarget", getTableName(checkoutDatePrev));
        List<ElectricityMeterHistoryData> listPrev = iElectricityMeterHistoryDataService
                .selectElectricityMeterHistoryDataLasted
                        (paramsRequeest);
        list.addAll(listPrev.stream().filter(e -> listTerminalId.contains(e.getTerminalId()))
                .collect(Collectors.toList()));
    }

    private void initRequestParamsE(LocalDateTime checkoutDate, Map<String, Object> paramsRequeest, LocalDateTime checkoutDatePrev) {
        paramsRequeest.put("supplierId", Supplier.DE_GAO.getId());
        paramsRequeest.put("tenantId", TENANT_ID);
        paramsRequeest.put("currentDate", checkoutDate.atZone(ZoneOffset.of("+8")).toEpochSecond());
        paramsRequeest.put("currentDatePrev", checkoutDatePrev.atZone(ZoneOffset.of("+8")).toEpochSecond());
        paramsRequeest.put("tableNameTarget", getTableName(checkoutDate));
    }

    private void addHistoryDataElectricity(ElectricityMeterHistoryData electricityMeterHistoryData, ElectricityTerminalsXb electricityTerminalsXb, BigDecimal lc) {
        BigDecimal positiveActiveEnergyS = electricityMeterHistoryData.getPositiveActiveEnergyS();
        BigDecimal  cyclesNum = ObjectUtils.isEmpty(electricityTerminalsXb.getCyclesNum())? BigDecimal.ZERO
                : new BigDecimal(electricityTerminalsXb.getCyclesNum());
        //设置展示读数
        electricityMeterHistoryData.setPositiveActiveEnergy(cyclesNum.multiply(lc).add(positiveActiveEnergyS));
        electricityMeterHistoryData.setCombinationActiveEnergy1(electricityMeterHistoryData.getPositiveActiveEnergy());
    }



}
